﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.ComponentModel;
using Dycox.ComponentModel;

namespace Dycox.Windows.Forms
{
    public class DataListView : ListView
    {
        public DataListView()
        {
            base.View = System.Windows.Forms.View.Details;
            base.FullRowSelect = true;
            
        }

        [Browsable(false)]
        public new ListViewItemCollection Items
        {
            get { return base.Items; }
        }

        [Browsable(false), DefaultValue(typeof(View), "Details")]
        public new View View
        {
            get { return base.View; }
            set { base.View = value; }
        }

        [Browsable(false), DefaultValue(true)]
        public new bool FullRowSelect
        {
            get { return base.FullRowSelect; }
            set { base.FullRowSelect = value; }
        }

        private object _dataSource;

        public object DataSource
        {
            get { return _dataSource; }
            set
            {
                if (_dataSource != value)
                {
                    SetDataSource(value);
                }
            }
        }

        private void SetDataSource(object dataSource)
        {
            _dataSource = dataSource;

            Action action = PerformDataBinding;

            if (this.InvokeRequired)
                this.Invoke(action);
            else
                action();
        }

        private IEnumerator GetDataSource()
        {
            IEnumerable enumerable = _dataSource as IEnumerable;

            if (enumerable != null)
                return enumerable.GetEnumerator();
            else
                return null;
        }

        private void PerformDataBinding()
        {
            this.BeginUpdate();

            ListViewItemCollection coll = this.Items;

            coll.Clear();

            IEnumerator dataSource = GetDataSource();
            if (dataSource != null)
            {
                while (dataSource.MoveNext())
                {
                    object dataItem = dataSource.Current;
                    DataListViewItem item = new DataListViewItem(dataItem);
                    DataListViewItemDataBindingEventArgs e = new DataListViewItemDataBindingEventArgs(item);
                    OnItemDataBinding(e);
                    if (!e.Cancel)
                    {
                        coll.Add(item);
                        item.PerformDataBinding();
                        OnItemDataBound(new DataListViewItemDataBoundEventArgs(item));
                    }
                }
            }

            this.EndUpdate();
        }

        public event DataListViewItemDataBoundEventHandler ItemDataBound;

        protected virtual void OnItemDataBound(DataListViewItemDataBoundEventArgs e)
        {
            if (ItemDataBound != null)
                ItemDataBound(this, e);
        }

        public event DataListViewItemDataBindingEventHandler ItemDataBinding;

        protected virtual void OnItemDataBinding(DataListViewItemDataBindingEventArgs e)
        {
            if (ItemDataBinding != null)
                ItemDataBinding(this, e);
        }

        private string _imageKeyDataMember;

        public string ImageKeyDataMember
        {
            get { return _imageKeyDataMember; }
            set { _imageKeyDataMember = value; }
        }


        public void AddColumns(ComponentModel.ModelView modelView)
        {
            if (modelView == null)
                throw new ArgumentNullException("modelView");

            AddColumns(modelView.GetFields(true));
        }

        public void AddColumns(ModelView modelView, object filter)
        {
            if (modelView == null)
                throw new ArgumentNullException("modelView");

            AddColumns(modelView.MatchFields(filter));
        }

        private void AddColumns(ViewField[] fields)
        {
            foreach (var fld in fields)
                Columns.Add(new DataColumnHeader(fld));
        }

        public void CheckItems(CheckItemsMethod method)
        {
            foreach (ListViewItem item in this.Items)
            {
                switch (method)
                {
                    case CheckItemsMethod.All:
                        item.Checked = true;
                        break;
                    case CheckItemsMethod.None:
                        item.Checked = false;
                        break;
                    case CheckItemsMethod.Invert:
                        item.Checked = !item.Checked;
                        break;
                    default:
                        break;
                }
            }
        }

        public T[] GetCheckedDataItems<T>()
        {
            return this.CheckedItems.OfType<DataListViewItem>().Select(o => (T)o.DataItem).ToArray();
        }

        public new DataListViewItem FocusedItem
        {
            get
            {
                return (DataListViewItem)base.FocusedItem;
            }
            set
            {
                base.FocusedItem = value;
            }
        }

        public new DataListViewItem GetItemAt(int x, int y)
        {
            return (DataListViewItem)base.GetItemAt(x, y);
        }
    }

    public class DataListViewItemDataBoundEventArgs : EventArgs
    {
        public DataListViewItemDataBoundEventArgs(DataListViewItem item)
        {
            if (item == null)
                throw new ArgumentNullException("item");
            _item = item;
        }

        private readonly DataListViewItem _item;

        public DataListViewItem Item
        {
            get { return _item; }
        }

    }

    public class DataListViewItemDataBindingEventArgs : DataListViewItemDataBoundEventArgs
    {
        public DataListViewItemDataBindingEventArgs(DataListViewItem item)
            : base(item)
        {

        }

        private bool _cancel;

        public bool Cancel
        {
            get { return _cancel; }
            set { _cancel = value; }
        }

    }

    public delegate void DataListViewItemDataBoundEventHandler(object sender, DataListViewItemDataBoundEventArgs e);

    public delegate void DataListViewItemDataBindingEventHandler(object sender, DataListViewItemDataBindingEventArgs e);
}
